package com.actor.networking;

import java.io.*;
import java.net.Socket;

/**
 * @author Dmitry
 */
public class NetworkConnection {
    private final DataInputStream inputStream;
    private final OutputStream outputStream;
    private final Socket socket;
    private final boolean authorized = false;
    private final NetworkContext networkContext;

    public NetworkConnection(Socket socket, NetworkContext networkContext) throws IOException {
        this.socket = socket;
        this.networkContext = networkContext;
        inputStream = new DataInputStream(socket.getInputStream());
        outputStream = new BufferedOutputStream(socket.getOutputStream(), 2048);
    }

    public boolean isAuthorized() {
        return authorized;
    }

    public void close() {
        try {
            inputStream.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        try {
            outputStream.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        try {
            socket.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public DataInputStream getInputStream() {
        return inputStream;
    }

    public OutputStream getOutputStream() {
        return outputStream;
    }

    public static int toInt(byte[] bytes) {
        int ret = 0;
        for (int i = 0; i < 4 && i < bytes.length; i++) {
            ret <<= 8;
            ret |= (int) bytes[i] & 0xFF;
        }

        return ret;
    }

    public static final byte[] intToByteArray(int value, byte[] buffer) {
        buffer[0] = (byte) (value >>> 24);
        buffer[1] = (byte) (value >>> 16);
        buffer[2] = (byte) (value >>> 8);
        buffer[3] = (byte) (value);
        return buffer;
    }

    private final byte[] readLengthBuffer = new byte[4];
    private final byte[] writeLengthBuffer = new byte[4];

    public NetworkMessage readMessage() {
        try {
            inputStream.readFully(readLengthBuffer);
            int length = toInt(readLengthBuffer);
            byte[] buffer = new byte[length];
            inputStream.readFully(buffer);
            return networkContext.getSerializer().deserialize(buffer);
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException("Cannot read networkmessage from InputStream");
        }
    }

    public void sendMessage(NetworkMessage message) {
        try {
            byte[] bytes = networkContext.getSerializer().serialize(message);
            intToByteArray(bytes.length, writeLengthBuffer);
            outputStream.write(writeLengthBuffer);
            outputStream.write(bytes);
            outputStream.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException("Cannot read networkmessage from InputStream");
        }
    }

}
